//////////////////////////////////////////////////////////////////////
////                                                              ////
////  File name: eth_phy.v                                        ////
////                                                              ////
////  This file is part of the Ethernet IP core project           ////
////  http://www.opencores.org/projects/ethmac/                   ////
////                                                              ////
////  Author(s):                                                  ////
////      - Tadej Markovic, tadej@opencores.org                   ////
////                                                              ////
////  All additional information is available in the README.txt   ////
////  file.                                                       ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2002  Authors                                  ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source is distributed in the hope that it will be       ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
//// PURPOSE.  See the GNU Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
//
// CVS Revision History
//
// $Log: not supported by cvs2svn $
// Revision 1.7  2002/10/18 13:58:22  tadejm
// Some code changed due to bug fixes.
//
// Revision 1.6  2002/10/09 13:16:51  tadejm
// Just back-up; not completed testbench and some testcases are not
// wotking properly yet.
//
// Revision 1.5  2002/09/18 17:55:08  tadej
// Bug repaired in eth_phy device
//
// Revision 1.3  2002/09/13 14:50:15  mohor
// Bug in MIIM fixed.
//
// Revision 1.2  2002/09/13 12:29:14  mohor
// Headers changed.
//
// Revision 1.1  2002/09/13 11:57:20  mohor
// New testbench. Thanks to Tadej M - "The Spammer".
//
//
//

`include "timescale.v"
`include "eth_phy_defines.v"

// ORPSoCv2 testbench include
// Will enable verbose if eth test
`ifdef TEST_DEFINE_FILE
 `include "test_define.v"
`endif


`define MULTICAST_XFR          0
`define UNICAST_XFR            1
`define BROADCAST_XFR          2
`define UNICAST_WRONG_XFR      3


`define ETH_PHY_VERBOSE 1

module eth_phy // This PHY model simulate simplified Intel LXT971A PHY
  (
   // COMMON
   m_rst_n_i,

   // MAC TX
   mtx_clk_o,
   mtxd_i,
   mtxen_i,
   mtxerr_i,

   // MAC RX
   mrx_clk_o,
   mrxd_o,
   mrxdv_o,
   mrxerr_o,

   // SMII signals
   smii_clk_i,
   smii_sync_i,
   smii_rx_o,
   
   mcoll_o,
   mcrs_o,

   // MIIM
   mdc_i,
   md_io,
   speed_o,
   link_o,
   duplex_o
   );

   //////////////////////////////////////////////////////////////////////
	 //
   // Input/output signals
   //
   //////////////////////////////////////////////////////////////////////

   // MAC miscellaneous signals
   input           m_rst_n_i;
   // MAC TX signals
   output          mtx_clk_o;
   input [3:0] 	   mtxd_i;
   input           mtxen_i;
   input           mtxerr_i;
   // MAC RX signals
   output          mrx_clk_o;
   output [3:0]    mrxd_o;
   output          mrxdv_o;
   output          mrxerr_o;
   // SMII RX signals
   input 	   smii_clk_i;
   input 	   smii_sync_i;
   output 	   smii_rx_o;
   
   // MAC common signals
   output          mcoll_o;
   output          mcrs_o;
   // MAC management signals
   input           mdc_i;
   inout           md_io;
   // Sideband signals for SMII -- jb
   output 	   link_o;
   output 	   speed_o;
   output 	   duplex_o;
   

   //////////////////////////////////////////////////////////////////////
   //
   // PHY management (MIIM) REGISTER definitions
   //
   //////////////////////////////////////////////////////////////////////
   //
   //   Supported registers:
   //
   // Addr | Register Name
   //--------------------------------------------------------------------
   //   0  | Control reg.     |
   //   1  | Status reg. #1   |--> normal operation
   //   2  | PHY ID reg. 1    |
   //   3  | PHY ID reg. 2    |
   //----------------------
   // Addr | Data MEMORY      |-->  for testing
   //
   //--------------------------------------------------------------------
   //
   // Control register
   reg 		   control_bit15; // self clearing bit
   reg [14:10] 	   control_bit14_10 = 5'b01000; // Init to 100MBPs (speed set)
   reg 		   control_bit9; // self clearing bit
   reg [8:0] 	   control_bit8_0;
   // Status register
   wire [15:9] 	   status_bit15_9 = `SUPPORTED_SPEED_AND_PORT;
   wire 	   status_bit8    = `EXTENDED_STATUS;
   wire 	   status_bit7    = 1'b0; // reserved
   reg [6:0] 	   status_bit6_0;
   // PHY ID register 1
   wire [15:0] 	   phy_id1        = `PHY_ID1;
   // PHY ID register 2
   wire [15:0] 	   phy_id2        = {`PHY_ID2, `MAN_MODEL_NUM, `MAN_REVISION_NUM};
   //--------------------------------------------------------------------
   //
   // Data MEMORY
   reg [15:0] 	   data_mem [0:31]; // 32 locations of 16-bit data width
   //
   //////////////////////////////////////////////////////////////////////


   //////////////////////////////////////////////////////////////////////
   //
   // PHY clocks - RX & TX
   //
   //////////////////////////////////////////////////////////////////////

   reg 		   mtx_clk_o;
   reg 		   mrx_clk_o;

   // random generator for a RX period when link is down
   real 	   rx_link_down_halfperiod;

   always@(status_bit6_0[2])
     begin
	if (!status_bit6_0[2]) // Link is down
	  begin
	     #1 rx_link_down_halfperiod = ({$random} % 243) + 13;
`ifdef ETH_PHY_VERBOSE
	     #1 $display( "(%0t)(%m)MAC RX clock is %f MHz while ethernet link is down!", 
			  $time, (1000/(rx_link_down_halfperiod*2)) );
`endif
	  end
     end

`ifdef ETH_PHY_VERBOSE
   always@(status_bit6_0[2])
     begin
	if (!status_bit6_0[2]) // Link is down
	  #1 $display( "(%0t)(%m)Ethernet link is down!", $time);
	else
	  #1 $display( "(%0t)(%m)Ethernet link is up!", $time);
     end
`endif

   // speed selection signal eth_speed: 1'b1 - 100 Mbps, 1'b0 - 10 Mbps
   wire      eth_speed;

   assign eth_speed = ( (control_bit14_10[13]) && !((`LED_CFG1) && (`LED_CFG2)) );

`ifdef ETH_PHY_VERBOSE
   always@(eth_speed)
     begin
	if (eth_speed)
	  #1 $display( "(%0t)(%m)PHY configured to 100 Mbps!", $time);
	else
	  #1 $display( "(%0t)(%m)PHY configured tp 10 Mbps!", $time);
     end
`endif

   // different clock calculation between RX and TX, so that there is alsways a litle difference
   /*initial
    begin
    set_mrx_equal_mtx = 1; // default
end*/

   always
     begin
	mtx_clk_o = 0;
	#7;
	forever
	  begin
	     if (eth_speed) // 100 Mbps - 25 MHz, 40 ns
	       begin
		  #20 mtx_clk_o = ~mtx_clk_o;
	       end
	     else // 10 Mbps - 2.5 MHz, 400 ns
	       begin
		  #200 mtx_clk_o = ~mtx_clk_o;
	       end
	  end
     end

   always
     begin
	// EQUAL mrx_clk to mtx_clk
	mrx_clk_o = 0;
	#7;
	forever
	  begin
	     if (eth_speed) // 100 Mbps - 25 MHz, 40 ns
	       begin
		  #20 mrx_clk_o = ~mrx_clk_o;
	       end
	     else // 10 Mbps - 2.5 MHz, 400 ns
	       begin
		  #200 mrx_clk_o = ~mrx_clk_o;
	       end
	  end
	// DIFFERENT mrx_clk than mtx_clk
	/*  mrx_clk_diff_than_mtx = 1;
	 #3;
	 forever
	 begin
	 if (status_bit6_0[2]) // Link is UP
	 begin
	 if (eth_speed) // 100 Mbps - 25 MHz, 40 ns
	 begin
         //#(((1/0.025001)/2)) 
         #19.99 mrx_clk_diff_than_mtx = ~mrx_clk_diff_than_mtx; // period is calculated from frequency in GHz
      end
	 else // 10 Mbps - 2.5 MHz, 400 ns
	 begin
         //#(((1/0.0024999)/2)) 
         #200.01 mrx_clk_diff_than_mtx = ~mrx_clk_diff_than_mtx; // period is calculated from frequency in GHz
      end
    end
	 else // Link is down
	 begin
	 #(rx_link_down_halfperiod) mrx_clk_diff_than_mtx = ~mrx_clk_diff_than_mtx; // random frequency between 2 MHz and 40 MHz
    end
  end*/
	//  // set output mrx_clk
	//  if (set_mrx_equal_mtx)
	//    mrx_clk_o = mrx_clk_equal_to_mtx;
	//  else
	//    mrx_clk_o = mrx_clk_diff_than_mtx;
     end

   // set output mrx_clk
   //assign mrx_clk_o = set_mrx_equal_mtx ? mrx_clk_equal_to_mtx : mrx_clk_diff_than_mtx ;

   //////////////////////////////////////////////////////////////////////
   //
   // PHY management (MIIM) interface
   //
   //////////////////////////////////////////////////////////////////////
   reg             respond_to_all_phy_addr; // PHY will respond to all phy addresses
   reg             no_preamble; // PHY responds to frames without preamble

   integer         md_transfer_cnt; // counter countes the value of whole data transfer
   reg             md_transfer_cnt_reset; // for reseting the counter
   reg             md_io_reg; // registered input
   reg             md_io_output; // registered output
   reg             md_io_rd_wr;  // op-code latched (read or write)
   reg             md_io_enable; // output enable
   reg [4:0] 	   phy_address; // address of PHY device
   reg [4:0] 	   reg_address; // address of a register
   reg             md_get_phy_address; // for shifting PHY address in
   reg             md_get_reg_address; // for shifting register address in
   reg [15:0] 	   reg_data_in; // data to be written in a register
   reg             md_get_reg_data_in; // for shifting data in
   reg             md_put_reg_data_in; // for storing data into a selected register
   reg [15:0] 	   reg_data_out; // data to be read from a register
   reg             md_put_reg_data_out; // for registering data from a selected register

   wire [15:0] 	   register_bus_in; // data bus to a selected register
   reg [15:0] 	   register_bus_out; // data bus from a selected register

   initial
     begin
	md_io_enable = 1'b0;
	respond_to_all_phy_addr = 1'b0;
	no_preamble = 1'b0;
     end

   // tristate output
   assign #1 md_io = (m_rst_n_i && md_io_enable) ? md_io_output : 1'bz ;

   // registering input
   always@(posedge mdc_i or negedge m_rst_n_i)
     begin
	if (!m_rst_n_i)
	  md_io_reg <= #1 0;
	else
	  md_io_reg <= #1 md_io;
     end

   // getting (shifting) PHY address, Register address and Data in
   // putting Data out and shifting
   always@(posedge mdc_i or negedge m_rst_n_i)
     begin
	if (!m_rst_n_i)
	  begin
	     phy_address <= 0;
	     reg_address <= 0;
	     reg_data_in <= 0;
	     reg_data_out <= 0;
	     md_io_output <= 0;
	  end
	else
	  begin
	     if (md_get_phy_address)
	       begin
		  phy_address[4:1] <= phy_address[3:0]; // correct address is `ETH_PHY_ADDR
		  phy_address[0]   <= md_io;
	       end
	     if (md_get_reg_address)
	       begin
		  reg_address[4:1] <= reg_address[3:0];
		  reg_address[0]   <= md_io;
	       end
	     if (md_get_reg_data_in)
	       begin
		  reg_data_in[15:1] <= reg_data_in[14:0];
		  reg_data_in[0]    <= md_io;
	       end
	     if (md_put_reg_data_out)
	       begin
		  reg_data_out <= register_bus_out;
	       end
	     if (md_io_enable)
	       begin
		  md_io_output       <= reg_data_out[15];
		  reg_data_out[15:1] <= reg_data_out[14:0];
		  reg_data_out[0]    <= 1'b0;
	       end
	  end
     end

   assign #1 register_bus_in = reg_data_in; // md_put_reg_data_in - allows writing to a selected register

   // counter for transfer to and from MIIM
   always@(posedge mdc_i or negedge m_rst_n_i)
     begin
	if (!m_rst_n_i)
	  begin
	     if (no_preamble)
	       md_transfer_cnt <= 33;
	     else
	       md_transfer_cnt <= 1;
	  end
	else
	  begin
	     if (md_transfer_cnt_reset)
	       begin
		  if (no_preamble)
		    md_transfer_cnt <= 33;
		  else
		    md_transfer_cnt <= 1;
	       end
	     else if (md_transfer_cnt < 64)
	       begin
		  md_transfer_cnt <= md_transfer_cnt + 1'b1;
	       end
	     else
	       begin
		  if (no_preamble)
		    md_transfer_cnt <= 33;
		  else
		    md_transfer_cnt <= 1;
	       end
	  end
     end

   // MIIM transfer control
   always@(m_rst_n_i or md_transfer_cnt or md_io_reg or md_io_rd_wr or 
           phy_address or respond_to_all_phy_addr or no_preamble)
     begin
	#1;
	while ((m_rst_n_i) && (md_transfer_cnt <= 64))
	  begin
	     // reset the signal - put registered data in the register (when write)
	     // check preamble
	     if (md_transfer_cnt < 33)
	       begin
		  #4 md_put_reg_data_in = 1'b0;
		  if (md_io_reg !== 1'b1)
		    begin
		       #1 md_transfer_cnt_reset = 1'b1;
		    end
		  else
		    begin
		       #1 md_transfer_cnt_reset = 1'b0;
		    end
	       end

	     // check start bits
	     else if (md_transfer_cnt == 33)
	       begin
		  if (no_preamble)
		    begin
		       #4 md_put_reg_data_in = 1'b0;
		       if (md_io_reg === 1'b0)
			 begin
			    #1 md_transfer_cnt_reset = 1'b0;
			 end
		       else
			 begin
			    #1 md_transfer_cnt_reset = 1'b1;
			    //if ((md_io_reg !== 1'bz) && (md_io_reg !== 1'b1))
			    if (md_io_reg !== 1'bz)
			      begin
				 // ERROR - start !
`ifdef ETH_PHY_VERBOSE
				 $display( "*E (%0t)(%m)MIIM - wrong first start bit (without preamble)", $time);
`endif
				 #10 $stop;
			      end
			 end
		    end
		  else // with preamble
		    begin
		       #4 ;
`ifdef ETH_PHY_VERBOSE
		       $display( "(%0t)(%m)MIIM - 32-bit preamble received", $time);
`endif
		       // check start bit only if md_transfer_cnt_reset is inactive, because if
		       // preamble suppression was changed start bit should not be checked
		       if ((md_io_reg !== 1'b0) && (md_transfer_cnt_reset == 1'b0))
			 begin
			    // ERROR - start !
`ifdef ETH_PHY_VERBOSE
			    $display( "*E (%0t)(%m)MIIM - wrong first start bit", $time);
`endif
			    #10 $stop;
			 end
		    end
	       end

	     else if (md_transfer_cnt == 34)
	       begin
		  #4;
		  if (md_io_reg !== 1'b1)
		    begin
		       // ERROR - start !
		       #1;
`ifdef ETH_PHY_VERBOSE
		       if (no_preamble)
			 $display( "*E (%0t)(%m)MIIM - wrong second start bit (without preamble)", $time);
		       else
			 $display( "*E (%0t)(%m)MIIM - wrong second start bit", $time);
`endif
		       #10 $stop;
		    end
		  else
		    begin
`ifdef ETH_PHY_VERBOSE
		       if (no_preamble)
			 #1 $display( "(%0t)(%m)MIIM - 2 start bits received (without preamble)", $time);
		       else
			 #1 $display( "(%0t)(%m)MIIM - 2 start bits received", $time);
`endif
		    end
	       end

	     // register the op-code (rd / wr)
	     else if (md_transfer_cnt == 35)
	       begin
		  #4;
		  if (md_io_reg === 1'b1)
		    begin
		       #1 md_io_rd_wr = 1'b1;
		    end
		  else 
		    begin
		       #1 md_io_rd_wr = 1'b0;
		    end
	       end

	     else if (md_transfer_cnt == 36)
	       begin
		  #4;
		  if ((md_io_reg === 1'b0) && (md_io_rd_wr == 1'b1))
		    begin
		       #1 md_io_rd_wr = 1'b1; // reading from PHY registers
`ifdef ETH_PHY_VERBOSE
		       $display( "(%0t)(%m)MIIM - op-code for READING from registers", $time);
`endif
		    end
		  else if ((md_io_reg === 1'b1) && (md_io_rd_wr == 1'b0))
		    begin
		       #1 md_io_rd_wr = 1'b0; // writing to PHY registers
`ifdef ETH_PHY_VERBOSE
		       $display( "(%0t)(%m)MIIM - op-code for WRITING to registers", $time);
`endif
		    end
		  else
		    begin
		       // ERROR - wrong opcode !
`ifdef ETH_PHY_VERBOSE
		       #1 $display( "*E (%0t)(%m)MIIM - wrong OP-CODE", $time);
`endif
		       #10 $stop;
		    end
		  // set the signal - get PHY address
		  begin
		     #1 md_get_phy_address = 1'b1;
		  end
	       end

	     // reset the signal - get PHY address
	     else if (md_transfer_cnt == 41)
	       begin
		  #4 md_get_phy_address = 1'b0;
		  // set the signal - get register address
		  #1 md_get_reg_address = 1'b1;
	       end

	     // reset the signal - get register address
	     // set the signal - put register data to output register
	     else if (md_transfer_cnt == 46)
	       begin
		  #4 md_get_reg_address = 1'b0;
		  #1 md_put_reg_data_out = 1'b1;
	       end

	     // reset the signal - put register data to output register
	     // set the signal - enable md_io as output when read
	     else if (md_transfer_cnt == 47)
	       begin
		  #4 md_put_reg_data_out = 1'b0;
		  if (md_io_rd_wr) //read
		    begin
		       if (md_io_reg !== 1'bz)
			 begin
			    // ERROR - turn around !
`ifdef ETH_PHY_VERBOSE
			    #1 $display( "*E (%0t)(%m)MIIM - wrong turn-around cycle before reading data out", $time);
`endif
			    #10 $stop;
			 end
		       if ((phy_address === `ETH_PHY_ADDR) || respond_to_all_phy_addr) // check the PHY address
			 begin
			    #1 md_io_enable = 1'b1;
`ifdef ETH_PHY_VERBOSE
			    $display( "(%0t)(%m)MIIM - received correct PHY ADDRESS: %x", $time, phy_address);
`endif
			 end
		       else
			 begin
`ifdef ETH_PHY_VERBOSE
			    #1 $display( "*W (%0t)(%m)MIIM - received different PHY ADDRESS: %x", $time, phy_address);
`endif
			 end
		    end
		  else // write
		    begin
		       #1 md_io_enable = 1'b0;
		       // check turn around cycle when write on clock 47
		       if (md_io_reg !== 1'b1) 
			 begin
			    // ERROR - turn around !
`ifdef ETH_PHY_VERBOSE
			    #1 $display( "*E (%0t)(%m)MIIM - wrong 1. turn-around cycle before writing data in", 
					 $time);
`endif
			    #10 $stop;
			 end
		    end
	       end

	     // set the signal - get register data in when write
	     else if (md_transfer_cnt == 48)
	       begin
		  #4;
		  if (!md_io_rd_wr) // write
		    begin
		       #1 md_get_reg_data_in = 1'b1;
		       // check turn around cycle when write on clock 48
		       if (md_io_reg !== 1'b0)
			 begin
			    // ERROR - turn around !
`ifdef ETH_PHY_VERBOSE
			    #1 $display( "*E (%0t)(%m)MIIM - wrong 2. turn-around cycle before writing data in", 
					 $time);
`endif
			    #10 $stop;
			 end
		    end
		  else // read
		    begin
		       #1 md_get_reg_data_in = 1'b0;
		    end
	       end

	     // reset the signal - enable md_io as output when read
	     // reset the signal - get register data in when write
	     // set the signal - put registered data in the register when write
	     else if (md_transfer_cnt == 64)
	       begin
		  #1 md_io_enable = 1'b0;
		  #4 md_get_reg_data_in = 1'b0;
		  if (!md_io_rd_wr) // write
		    begin
		       if ((phy_address === `ETH_PHY_ADDR) || respond_to_all_phy_addr) // check the PHY address
			 begin
			    #1 md_put_reg_data_in = 1'b1;
`ifdef ETH_PHY_VERBOSE
			    $display( "(%0t)(%m)MIIM - received correct PHY ADDRESS: %x", $time, phy_address);
			    $display( "(%0t)(%m)MIIM - WRITING to register %x COMPLETED!", $time, reg_address);
`endif
			 end
		       else
			 begin
`ifdef ETH_PHY_VERBOSE
			    #1 $display( "*W (%0t)(%m)MIIM - received different PHY ADDRESS: %x", $time, phy_address);
			    $display( "*W (%0t)(%m)MIIM - NO WRITING to register %x !", $time, reg_address);
`endif
			 end
		    end
		  else // read
		    begin
`ifdef ETH_PHY_VERBOSE
		       if ((phy_address === `ETH_PHY_ADDR) || respond_to_all_phy_addr) // check the PHY address
			 #1 $display( "(%0t)(%m)MIIM - READING from register %x COMPLETED!", 
				      $time, reg_address);
		       else
			 #1 $display( "*W (%0t)(%m)MIIM - NO READING from register %x !", $time, reg_address);
`endif
		    end
	       end

	     // wait for one clock period
	     @(posedge mdc_i)
	       #1;
	  end 
     end

   //====================================================================
   //
   // PHY management (MIIM) REGISTERS
   //
   //====================================================================
   //
   //   Supported registers (normal operation):
   //
   // Addr | Register Name 
   //--------------------------------------------------------------------
   //   0  | Control reg.  
   //   1  | Status reg. #1 
   //   2  | PHY ID reg. 1 
   //   3  | PHY ID reg. 2 
   //----------------------
   // Addr | Data MEMORY      |-->  for testing
   //
   //--------------------------------------------------------------------
   //
   // Control register
   //  reg            control_bit15; // self clearing bit
   //  reg    [14:10] control_bit14_10;
   //  reg            control_bit9; // self clearing bit
   //  reg    [8:0]   control_bit8_0;
   // Status register
   //  wire   [15:9]  status_bit15_9 = `SUPPORTED_SPEED_AND_PORT;
   //  wire           status_bit8    = `EXTENDED_STATUS;
   //  wire           status_bit7    = 1'b0; // reserved
   //  reg    [6:0]   status_bit6_0  = `DEFAULT_STATUS;
   // PHY ID register 1
   //  wire   [15:0]  phy_id1        = `PHY_ID1;
   // PHY ID register 2
   //  wire   [15:0]  phy_id2        = {`PHY_ID2, `MAN_MODEL_NUM, `MAN_REVISION_NUM};
   //--------------------------------------------------------------------
   //
   // Data MEMORY
   //  reg    [15:0]  data_mem [0:31]; // 32 locations of 16-bit data width
   //
   //====================================================================

   //////////////////////////////////////////////////////////////////////
   //
   // PHY management (MIIM) REGISTER control
   //
   //////////////////////////////////////////////////////////////////////

   // wholy writable registers for walking ONE's on data, phy and reg. addresses
   reg     registers_addr_data_test_operation;

   // Non writable status registers
   initial // always
     begin
	#1 status_bit6_0[6] = no_preamble;
	status_bit6_0[5] = 1'b0;
	status_bit6_0[3] = 1'b1;
	status_bit6_0[0] = 1'b1;
     end
   always@(posedge mrx_clk_o)
     begin
	status_bit6_0[4] <= #1 1'b0;
	status_bit6_0[1] <= #1 1'b0;
     end
   initial
     begin
	status_bit6_0[2] = 1'b1;
	registers_addr_data_test_operation = 0;
     end

   // Reading from a selected registers
   always@(reg_address or registers_addr_data_test_operation or md_put_reg_data_out or
           control_bit15 or control_bit14_10 or control_bit9 or control_bit8_0 or 
           status_bit15_9 or status_bit8 or status_bit7 or status_bit6_0 or
           phy_id1 or phy_id2)
     begin
	if (registers_addr_data_test_operation) // test operation
	  begin
	     if (md_put_reg_data_out) // read enable
	       begin
		  register_bus_out = #1 data_mem[reg_address];
	       end
	  end
	else // normal operation
	  begin
	     if (md_put_reg_data_out) // read enable
	       begin
		  case (reg_address)
		    5'h0:    register_bus_out = #1 {control_bit15, control_bit14_10, control_bit9, control_bit8_0};
		    5'h1:    register_bus_out = #1 {status_bit15_9, status_bit8, status_bit7, status_bit6_0};
		    5'h2:    register_bus_out = #1 phy_id1;
		    5'h3:    register_bus_out = #1 phy_id2;
		    default: register_bus_out = #1 16'hDEAD;
		  endcase
	       end
	  end
     end

   // Self clear control signals
   reg    self_clear_d0;
   reg    self_clear_d1;
   reg    self_clear_d2;
   reg    self_clear_d3;
   // Self clearing control
   always@(posedge mdc_i or negedge m_rst_n_i)
     begin
	if (!m_rst_n_i)
	  begin
	     self_clear_d0    <= #1 0;
	     self_clear_d1    <= #1 0;
	     self_clear_d2    <= #1 0;
	     self_clear_d3    <= #1 0;
	  end
	else
	  begin
	     self_clear_d0    <= #1 md_put_reg_data_in;
	     self_clear_d1    <= #1 self_clear_d0;
	     self_clear_d2    <= #1 self_clear_d1;
	     self_clear_d3    <= #1 self_clear_d2;
	  end
     end

   // Writing to a selected register
   always@(posedge mdc_i or negedge m_rst_n_i)
     begin
	if ((!m_rst_n_i) || (control_bit15))
	  begin
	     if (!registers_addr_data_test_operation) // normal operation
	       begin
		  control_bit15    <= #1 0;
		  control_bit14_10 <= #1 {1'b0, (`LED_CFG1 || `LED_CFG2), `LED_CFG1, 2'b0};
		  control_bit9     <= #1 0;
		  control_bit8_0   <= #1 {`LED_CFG3, 8'b0};
	       end
	  end
	else
	  begin
	     if (registers_addr_data_test_operation) // test operation
	       begin
		  if (md_put_reg_data_in)
		    begin
		       data_mem[reg_address] <= #1 register_bus_in[15:0];
		    end
	       end
	     else // normal operation
	       begin
		  // bits that are normaly written
		  if (md_put_reg_data_in)
		    begin
		       case (reg_address)
			 5'h0: 
			   begin
			      control_bit14_10 <= #1 register_bus_in[14:10];
			      control_bit8_0   <= #1 register_bus_in[8:0];
			   end
			 default:
			   begin
			   end
		       endcase
		    end
		  // self cleared bits written
		  if ((md_put_reg_data_in) && (reg_address == 5'h0))
		    begin
		       control_bit15 <= #1 register_bus_in[15];
		       control_bit9  <= #1 register_bus_in[9];
		    end
		  else if (self_clear_d3) // self cleared bits cleared
		    begin
		       control_bit15 <= #1 1'b0;
		       control_bit9  <= #1 1'b0;
		    end
	       end
	  end
     end

   //////////////////////////////////////////////////////////////////////
	 //
   // PHY <-> MAC control (RX and TX clocks are at the begining)
   //
   //////////////////////////////////////////////////////////////////////

   // CARRIER SENSE & COLLISION

   // MAC common signals
   reg             mcoll_o;
   reg             mcrs_o;
   // Internal signals controling Carrier sense & Collision
   // MAC common signals generated when appropriate transfer
   reg             mcrs_rx;
   reg             mcrs_tx;
   // delayed mtxen_i signal for generating delayed tx carrier sense
   reg             mtxen_d1;
   reg             mtxen_d2;
   reg             mtxen_d3;
   reg             mtxen_d4;
   reg             mtxen_d5;
   reg             mtxen_d6;
   // collision signal set or rest within task for controling collision
   reg             task_mcoll;
   // carrier sense signal set or rest within task for controling carrier sense
   reg             task_mcrs;
   reg             task_mcrs_lost;
   // do not generate collision in half duplex - not normal operation
   reg             no_collision_in_half_duplex;
   // generate collision in full-duplex mode also - not normal operation
   reg             collision_in_full_duplex;
   // do not generate carrier sense in half duplex mode - not normal operation
   reg             no_carrier_sense_in_tx_half_duplex;
   reg             no_carrier_sense_in_rx_half_duplex;
   // generate carrier sense during TX in full-duplex mode also - not normal operation
   reg             carrier_sense_in_tx_full_duplex;
   // do not generate carrier sense during RX in full-duplex mode - not normal operation
   reg             no_carrier_sense_in_rx_full_duplex;
   // on RX: delay after carrier sense signal; on TX: carrier sense delayed (delay is one clock period)
   reg             real_carrier_sense;

   initial
     begin
	mcrs_rx = 0;
	mcrs_tx = 0;
	task_mcoll = 0;
	task_mcrs = 0;
	task_mcrs_lost = 0;
	no_collision_in_half_duplex = 0;
	collision_in_full_duplex = 0;
	no_carrier_sense_in_tx_half_duplex = 0;
	no_carrier_sense_in_rx_half_duplex = 0;
	carrier_sense_in_tx_full_duplex = 0;
	no_carrier_sense_in_rx_full_duplex = 0;
	real_carrier_sense = 0;
     end

   // Collision
   always@(m_rst_n_i or control_bit8_0 or collision_in_full_duplex or 
           mcrs_rx or mcrs_tx or task_mcoll or no_collision_in_half_duplex
           )
     begin
	if (!m_rst_n_i)
	  mcoll_o = 0;
	else
	  begin
	     if (control_bit8_0[8]) // full duplex
	       begin
		  if (collision_in_full_duplex) // collision is usually not asserted in full duplex
		    begin
		       mcoll_o = ((mcrs_rx && mcrs_tx) || task_mcoll);
`ifdef ETH_PHY_VERBOSE
		       if (mcrs_rx && mcrs_tx)
			 $display( "(%0t)(%m) Collision set in FullDuplex!", $time);
		       if (task_mcoll)
			 $display( "(%0t)(%m) Collision set in FullDuplex from TASK!", $time);
`endif
		    end
		  else
		    begin
		       mcoll_o = task_mcoll;
`ifdef ETH_PHY_VERBOSE
		       if (task_mcoll)
			 $display( "(%0t)(%m) Collision set in FullDuplex from TASK!", $time);
`endif
		    end
	       end
	     else // half duplex
	       begin
		  mcoll_o = ((mcrs_rx && mcrs_tx && !no_collision_in_half_duplex) || 
			     task_mcoll);
`ifdef ETH_PHY_VERBOSE
		  if (mcrs_rx && mcrs_tx)
		    $display( "(%0t)(%m) Collision set in HalfDuplex!", $time);
		  if (task_mcoll)
		    $display( "(%0t)(%m) Collision set in HalfDuplex from TASK!", $time);
`endif
	       end
	  end
     end

   // Carrier sense
   always@(m_rst_n_i or control_bit8_0 or carrier_sense_in_tx_full_duplex or
           no_carrier_sense_in_rx_full_duplex or
           no_carrier_sense_in_tx_half_duplex or 
           no_carrier_sense_in_rx_half_duplex or 
           mcrs_rx or mcrs_tx or task_mcrs or task_mcrs_lost
           )
     begin
	if (!m_rst_n_i)
	  mcrs_o = 0;
	else
	  begin
	     if (control_bit8_0[8]) // full duplex
	       begin
		  if (carrier_sense_in_tx_full_duplex) // carrier sense is usually not asserted during TX in full duplex
		    mcrs_o = ((mcrs_rx && !no_carrier_sense_in_rx_full_duplex) || 
			      mcrs_tx || task_mcrs) && !task_mcrs_lost;
		  else
		    mcrs_o = ((mcrs_rx && !no_carrier_sense_in_rx_full_duplex) || 
			      task_mcrs) && !task_mcrs_lost;
	       end
	     else // half duplex
	       begin
		  mcrs_o = ((mcrs_rx && !no_carrier_sense_in_rx_half_duplex) || 
			    (mcrs_tx && !no_carrier_sense_in_tx_half_duplex) || 
			    task_mcrs) && !task_mcrs_lost;
	       end
	  end
     end

   // MAC TX CONTROL (RECEIVING AT PHY)

   // storage memory for TX data received from MAC
   reg     [7:0]  tx_mem [0:4194303]; // 4194304 locations (22 address lines) of 8-bit data width
   reg [31:0] 	  tx_mem_addr_in; // address for storing to TX memory
   reg [7:0] 	  tx_mem_data_in; // data for storing to TX memory
   reg [31:0] 	  tx_cnt; // counts nibbles

   // control data of a TX packet for upper layer of testbench
   reg            tx_preamble_ok;
   reg            tx_sfd_ok;
   // if there is a drible nibble, then tx packet is not byte aligned!
   reg            tx_byte_aligned_ok;
   // complete length of TX packet (Bytes) received (without preamble and SFD)
   reg [31:0] 	  tx_len;
   // complete length of TX packet (Bytes) received (without preamble and SFD) untill MTxErr signal was set first
   reg [31:0] 	  tx_len_err;

   // TX control
   always@(posedge mtx_clk_o)
     begin
	// storing data and basic checking of frame
	if (!m_rst_n_i)
	  begin
	     tx_cnt <= 0;
	     tx_preamble_ok <= 0;
	     tx_sfd_ok <= 0;
	     tx_len <= 0;
	     tx_len_err <= 0;
	  end
	else
	  begin
	     if (!mtxen_i)
	       begin
		  tx_cnt <= 0;
	       end
	     else
	       begin
		  // tx nibble counter
		  tx_cnt <= tx_cnt + 1;
		  // set initial values and check first preamble nibble
		  if (tx_cnt == 0)
		    begin
`ifdef ETH_PHY_VERBOSE
		       $display( "(%0t)(%m) TX frame started with tx_en set!", $time);
`endif
		       if (mtxd_i == 4'h5)
			 tx_preamble_ok <= 1;
		       else
			 tx_preamble_ok <= 0;
		       tx_sfd_ok <= 0;
		       tx_byte_aligned_ok <= 0;
		       tx_len <= 0;
		       tx_len_err <= 0;
		       tx_mem_addr_in <= 0; // RESET this here each packet! 
		    end

		  // check preamble
		  if ((tx_cnt > 0) && (tx_cnt <= 13))
		    begin
		       if ((tx_preamble_ok != 1) || (mtxd_i != 4'h5))
			 tx_preamble_ok <= 0;
		    end
		  // check SFD
		  if (tx_cnt == 14)
		    begin
`ifdef ETH_PHY_VERBOSE
		       if (tx_preamble_ok == 1)
			 $display( "(%0t)(%m) TX frame preamble OK!", $time);
		       else
			 $display( "*E (%0t)(%m) TX frame preamble NOT OK!", $time);
`endif
		       if (mtxd_i == 4'h5)
			 tx_sfd_ok <= 1;
		       else
			 tx_sfd_ok <= 0;
		    end
		  if (tx_cnt == 15)
		    begin
		       if ((tx_sfd_ok != 1) || (mtxd_i != 4'hD))
			 tx_sfd_ok <= 0;
		    end

		  // control for storing addresses, type/length, data and FCS to TX memory
		  if (tx_cnt > 15)
		    begin
		       if (tx_cnt == 16)
			 begin
`ifdef ETH_PHY_VERBOSE
			    if (tx_sfd_ok == 1)
			      $display( "(%0t)(%m) TX frame SFD OK!", $time);
			    else
			      $display( "*E (%0t)(%m) TX frame SFD NOT OK!", $time);
`endif
			 end

		       if (tx_cnt[0] == 0)
			 begin
			    tx_mem_data_in[3:0] <= mtxd_i; // storing LSB nibble
			    tx_byte_aligned_ok <= 0; // if transfer will stop after this, then there was drible nibble
			 end
		       else
			 begin
			    tx_mem[tx_mem_addr_in[21:0]] <= {mtxd_i, tx_mem_data_in[3:0]}; // storing data into tx memory
			    tx_len <= tx_len + 1; // enlarge byte length counter
			    tx_byte_aligned_ok <= 1; // if transfer will stop after this, then transfer is byte alligned
			    tx_mem_addr_in <= tx_mem_addr_in + 1'b1;
			 end

		       if (mtxerr_i)
			 tx_len_err <= tx_len;
		    end
	       end
	  end

	// generating CARRIER SENSE for TX with or without delay
	if (!m_rst_n_i)
	  begin
	     mcrs_tx  <= 0;
	     mtxen_d1 <= 0;
	     mtxen_d2 <= 0;
	     mtxen_d3 <= 0;
	     mtxen_d4 <= 0;
	     mtxen_d5 <= 0;
	     mtxen_d6 <= 0;
	  end
	else
	  begin
	     mtxen_d1 <= mtxen_i;
	     mtxen_d2 <= mtxen_d1;
	     mtxen_d3 <= mtxen_d2;
	     mtxen_d4 <= mtxen_d3;
	     mtxen_d5 <= mtxen_d4;
	     mtxen_d6 <= mtxen_d5;
	     if (real_carrier_sense)
	       mcrs_tx  <= mtxen_d6;
	     else
	       mcrs_tx  <= mtxen_i;
	  end
     end

`ifdef ETH_PHY_VERBOSE
   reg             frame_started;

   initial
     begin
	frame_started = 0;
     end
   always@(posedge mtxen_i)
     begin
	frame_started <= 1;
     end
   always@(negedge mtxen_i)
     begin
	if (frame_started)
	  begin
	     $display( "(%0t)(%m) TX frame ended with tx_en reset!", $time);
	     frame_started <= 0;
	  end
     end

   always@(posedge mrxerr_o)
     begin
	$display( "(%0t)(%m) RX frame ERROR signal was set!", $time);
     end
`endif

   //////////////////////////////////////////////////////////////////////
   // 
   // Tasks for PHY <-> MAC transactions
   // 
   //////////////////////////////////////////////////////////////////////

   initial
     begin
	tx_mem_addr_in = 0;
     end

   // setting the address of tx_mem, to set the starting point of tx packet
   task set_tx_mem_addr;
      input [31:0] tx_mem_address;
      begin
	 #1 tx_mem_addr_in = tx_mem_address;
      end
   endtask // set_tx_mem_addr

   // storage memory for RX data to be transmited to MAC
   //reg     [7:0]  rx_mem [0:4194303]; // 4194304 locations (22 address lines) of 8-bit data width
   reg     [7:0]  rx_mem [0:2000]; // Legal ethernet packet is 1512, so add a bit more for extras

   // MAC RX signals
   reg [3:0] 	  mrxd_o;
   reg 		  mrxdv_o;
   reg 		  mrxerr_o;

   // SMII signals
   reg 		  smii_rx_go;
   reg [31:0] 	  smii_rx_dat_addr;
   reg [10:1] 	  smii_rx_frame;
   reg [10:1] 	  smii_sync_state;
   reg [31:0] 	  smii_rx_len;
   
`define DEFAULT_SMII_RX_FRAME {3'b101,1'b0,1'b1,1'b1,eth_speed,1'b0,1'b0,1'b0}
   
   
   initial
     begin
	mrxd_o = 0;
	mrxdv_o = 0;
	mrxerr_o = 0;
	mcrs_rx = 0;
	smii_rx_go = 0;
	#100
	// For now hardcoded to 100Mbps
	smii_rx_frame = `DEFAULT_SMII_RX_FRAME;
     end


   always @(posedge smii_clk_i or negedge m_rst_n_i)
	if (!m_rst_n_i)
       smii_sync_state <= 10'b00000_00000;
     else if (smii_sync_i)
       smii_sync_state <= 10'b00000_00010;
     else
       smii_sync_state <= {smii_sync_state[9:1], smii_sync_state[10]};

   assign #2 smii_rx_o = |(smii_rx_frame & smii_sync_state);

   integer smii_frame_counter;
   
   // Update the SMII frame we'll put out next
   task smii_rx_new_frame;
      input [10:1] frame;
      begin
	 while (~smii_sync_state[10]) // Wait for state before sync to output data
	   @(posedge smii_clk_i);
	 #2;

	 // Set the frame out
	 smii_rx_frame = frame;

	 if (eth_speed == 0)
	   begin
	      // is 10Mbps mode, so repeat the frame 10 times
	      smii_frame_counter = 0;
	      while (smii_frame_counter < 10)
		begin
		   @(posedge smii_sync_state[10]);
		   smii_frame_counter  = smii_frame_counter + 1;
		end
	   end
      end
   endtask // smii_rx_new_frame

   always @(eth_speed)
     // Update frame
     smii_rx_new_frame(`DEFAULT_SMII_RX_FRAME);
      
   integer smii_rx_cnt;
   
   // SMII RX functions
   always @(posedge smii_rx_go)
     begin
	// SFD
	smii_rx_new_frame({8'h55,2'b10});
	smii_rx_new_frame({8'h55,2'b10});
	smii_rx_new_frame({8'h55,2'b10});
	smii_rx_new_frame({8'h55,2'b10});
	smii_rx_new_frame({8'h55,2'b10});
	smii_rx_new_frame({8'h55,2'b10});
	smii_rx_new_frame({8'h55,2'b10});
	smii_rx_new_frame({8'hd5,2'b10});

	// send packet's addresses, type/length, data and FCS
	 for (smii_rx_cnt = 0; smii_rx_cnt < smii_rx_len; smii_rx_cnt = smii_rx_cnt + 1)
	   begin
              smii_rx_new_frame({rx_mem[smii_rx_dat_addr[21:0]],2'b10});
              smii_rx_dat_addr = smii_rx_dat_addr + 1;
	   end
	// Set frame back to original
	smii_rx_new_frame(`DEFAULT_SMII_RX_FRAME);
	
	smii_rx_go = 0;
	
     end
   

   task send_rx_packet;
      input  [(8*8)-1:0] preamble_data; // preamble data to be sent - 
                                        // correct is 64'h0055_5555_5555_5555
      input [3:0] 	 preamble_len; // length of preamble in bytes - 
                                       // max is 4'h8, correct is 4'h7 
      input [7:0] 	 sfd_data; // SFD data to be sent - correct is 8'hD5
      input [31:0] 	 start_addr; // start address
      input [31:0] 	 len; // length of frame in Bytes (without preamble
                              // and SFD)
      input 		 plus_drible_nibble; // if length is longer for one 
                                             // nibble
      input 		 assert_rx_err; // Set rxerr during transmit
      begin
	 smii_rx_dat_addr = start_addr;
	 smii_rx_len = len;
	 smii_rx_go = 1;
	 
	 send_mii_rx_packet(preamble_data, preamble_len, sfd_data, start_addr, 
			    len, plus_drible_nibble, assert_rx_err);
`ifdef SMII0
	 while(smii_rx_go)
	   @(posedge smii_clk_i);
`endif
	 
      end
   endtask // send_rx_packet
   
   task send_mii_rx_packet;
      input  [(8*8)-1:0] preamble_data; // preamble data to be sent - 
                                        // correct is 64'h0055_5555_5555_5555
      input [3:0] 	 preamble_len; // length of preamble in bytes - 
                                       // max is 4'h8, correct is 4'h7 
      input [7:0] 	 sfd_data; // SFD data to be sent - correct is 8'hD5
      input [31:0] 	 start_addr; // start address
      input [31:0] 	 len; // length of frame in Bytes (without preamble
                              // and SFD)
      input 		 plus_drible_nibble; // if length is longer for one 
                                             // nibble
      input 		 assert_rx_err; // Set rxerr during transmit
      
      integer 		 rx_cnt;
      reg [31:0] 	 rx_mem_addr_in; // address for reading from RX memory
      reg [7:0] 	 rx_mem_data_out; // data for reading from RX memory
      begin
	 @(posedge mrx_clk_o);
	 // generating CARRIER SENSE for TX with or without delay
	 if (real_carrier_sense)
           #1 mcrs_rx = 1;
	 else
           #1 mcrs_rx = 0;
	 @(posedge mrx_clk_o);
	 #1 mcrs_rx = 1;
	 #1 mrxdv_o = 1;
`ifdef ETH_PHY_VERBOSE
	 $display( "(%0t)(%m) RX frame started with rx_dv set!", $time);
`endif
	 // set initial rx memory address
	 rx_mem_addr_in = start_addr;
	 
	 // send preamble
	 for (rx_cnt = 0; (rx_cnt < (preamble_len << 1)) && (rx_cnt < 16); 
	      rx_cnt = rx_cnt + 1)
	   begin
              #1 mrxd_o = preamble_data[3:0];
              #1 preamble_data = preamble_data >> 4;
              @(posedge mrx_clk_o);
	   end
	 
	 // send SFD
	 for (rx_cnt = 0; rx_cnt < 2; rx_cnt = rx_cnt + 1)
	   begin
              #1 mrxd_o = sfd_data[3:0];
              #1 sfd_data = sfd_data >> 4;
              @(posedge mrx_clk_o);
	   end
`ifdef ETH_PHY_VERBOSE
	 $display( "(%0t)(%m) RX frame preamble and SFD sent!", $time);
`endif
	 // send packet's addresses, type/length, data and FCS
	 for (rx_cnt = 0; rx_cnt < len; rx_cnt = rx_cnt + 1)
	   begin
              #1;
              rx_mem_data_out = rx_mem[rx_mem_addr_in[21:0]];
              mrxd_o = rx_mem_data_out[3:0];
              @(posedge mrx_clk_o);
              #1;
	      
	      // Assert error if told to .... TODO: make this occur at random 
	      //                                    time - JPB
	      
	      if (rx_cnt > 18) rx_err(assert_rx_err);
	      
              mrxd_o = rx_mem_data_out[7:4];
              rx_mem_addr_in = rx_mem_addr_in + 1;
              @(posedge mrx_clk_o);
              #1;
	   end
	 if (plus_drible_nibble)
	   begin
              rx_mem_data_out = rx_mem[rx_mem_addr_in[21:0]];
              mrxd_o = rx_mem_data_out[3:0];
              @(posedge mrx_clk_o);
	   end
`ifdef ETH_PHY_VERBOSE
	 $display( "(%0t)(%m) RX frame addresses, type/length, data and FCS sent!", $time);
`endif
	 #1 mcrs_rx = 0;
	 #1 mrxdv_o = 0;   
	 @(posedge mrx_clk_o);
`ifdef ETH_PHY_VERBOSE
	 $display( "(%0t)(%m) RX frame ended with rx_dv reset!", $time);
`endif            
      end
   endtask // send_rx_packet



   task GetDataOnMRxD;
      input [15:0] Len;
      input [31:0] TransferType;
      integer 	   tt;

      begin
	 @ (posedge mrx_clk_o);
	 #1 mrxdv_o=1'b1;

	 for(tt=0; tt<15; tt=tt+1)
	   begin
	      mrxd_o=4'h5;              // preamble
	      @ (posedge mrx_clk_o);
	      #1;
	   end

	 mrxd_o=4'hd;                // SFD

	 for(tt=1; tt<(Len+1); tt=tt+1)
	   begin
	      @ (posedge mrx_clk_o);
	      #1;
	      if(TransferType == `UNICAST_XFR && tt == 1)
		mrxd_o = 4'h0;   // Unicast transfer
	      else if(TransferType == `BROADCAST_XFR && tt < 7)
		mrxd_o = 4'hf;
	      else
		mrxd_o = tt[3:0]; // Multicast transfer

	      @ (posedge mrx_clk_o);
	      #1;

	      if(TransferType == `BROADCAST_XFR && tt == 6)
		mrxd_o = 4'he;
	      else

		if(TransferType == `BROADCAST_XFR && tt < 7)
		  mrxd_o = 4'hf;
		else
		  mrxd_o = tt[7:4];
	   end

	 @ (posedge mrx_clk_o);
	 #1;
	 mrxdv_o = 1'b0;
      end
   endtask // GetDataOnMRxD


   //////////////////////////////////////////////////////////////////////
   //
   // Tastks for controling PHY statuses and rx error
   //
   //////////////////////////////////////////////////////////////////////

   // Link control tasks
   task link_up_down;
      input   test_op;
      begin
	 #1 status_bit6_0[2] = test_op; // 1 - link up; 0 - link down
      end
   endtask

   // RX error
   task rx_err;
      input   test_op;
      begin
	 #1 mrxerr_o = test_op; // 1 - RX error set; 0 - RX error reset
      end
   endtask

   //////////////////////////////////////////////////////////////////////
   //
   // Tastks for controling PHY carrier sense and collision
   //
   //////////////////////////////////////////////////////////////////////

   // Collision
   task collision;
      input   test_op;
      begin
	 #1 task_mcoll = test_op;
      end
   endtask

   // Carrier sense
   task carrier_sense;
      input   test_op;
      begin
	 #1 task_mcrs = test_op;
      end
   endtask

   // Carrier sense lost - higher priority than Carrier sense task
   task carrier_sense_lost;
      input   test_op;
      begin
	 #1 task_mcrs_lost = test_op;
      end
   endtask

   // No collision detection in half duplex
   task no_collision_hd_detect;
      input   test_op;
      begin
	 #1 no_collision_in_half_duplex = test_op;
      end
   endtask

   // Collision detection in full duplex also
   task collision_fd_detect;
      input   test_op;
      begin
	 #1 collision_in_full_duplex = test_op;
      end
   endtask

   // No carrier sense detection at TX in half duplex
   task no_carrier_sense_tx_hd_detect;
      input   test_op;
      begin
	 #1 no_carrier_sense_in_tx_half_duplex = test_op;
      end
   endtask

   // No carrier sense detection at RX in half duplex
   task no_carrier_sense_rx_hd_detect;
      input   test_op;
      begin
	 #1 no_carrier_sense_in_rx_half_duplex = test_op;
      end
   endtask

   // Carrier sense detection at TX in full duplex also
   task carrier_sense_tx_fd_detect;
      input   test_op;
      begin
	 #1 carrier_sense_in_tx_full_duplex = test_op;
      end
   endtask

   // No carrier sense detection at RX in full duplex
   task no_carrier_sense_rx_fd_detect;
      input   test_op;
      begin
	 #1 no_carrier_sense_in_rx_full_duplex = test_op;
      end
   endtask

   // Set real delay on carrier sense signal (and therefor collision signal)
   task carrier_sense_real_delay;
      input   test_op;
      begin
	 #1 real_carrier_sense = test_op;
      end
   endtask

   //////////////////////////////////////////////////////////////////////
   //
   // Tastks for controling PHY management test operation
   //
   //////////////////////////////////////////////////////////////////////

   // Set registers to test operation and respond to all phy addresses
   task test_regs;
      input   test_op;
      begin
	 #1 registers_addr_data_test_operation = test_op;
	 respond_to_all_phy_addr = test_op;
      end
   endtask

   // Clears data memory for testing the MII
   task clear_test_regs;
      integer i;
      begin
	 for (i = 0; i < 32; i = i + 1)
	   begin
	      #1 data_mem[i] = 16'h0;
	   end
      end
   endtask

   // Accept frames with preamble suppresed
   task preamble_suppresed;
      input   test_op;
      begin
	 #1 no_preamble = test_op;
	 md_transfer_cnt_reset = 1'b1;
	 @(posedge mdc_i);
	 #1 md_transfer_cnt_reset = 1'b0;
      end
   endtask



   // Sideband signals for external SMII converter --jb
   assign link_o = status_bit6_0[2];
   
   assign speed_o = eth_speed;
   
   assign duplex_o = control_bit8_0[8];




endmodule

